在 ES6 新增兩種變數方法 let 、 const ,不過我們比較常把 const 叫做常數,主要是因為 var 的特性 容易觸發 Bug , 這邊與 var 的差異主要有:
在提及這些不同特性之前,先大致介紹一下這兩個用法的差別。
let  能夠重新賦值,但不能重複宣告
let String1 = 'test1'
String1 =  'test2'
let String1 = 'test3' // 重複宣告錯誤, Uncaught SyntaxError: Identifier 'String1' has already been declared
const  不能重新賦值,也不能重新宣告。
const String1 = 'test1'
const String1 = 'test2' //  重複宣告錯誤, Uncaught SyntaxError: Identifier 'String1' has already been declared
String1 = 'test3' // 賦值錯誤, Uncaught TypeError: invalid assignment to const 'String1'
要補充一點如果 const 的值是物件,對物件底下的屬性賦值,  const 則能接受這種操作繼續使用。
const obj = {}
obj.name = 'Ryder'
console.log(obj) // { name: 'Ryder' }
const array = []
array.push(1)
console.log(array) // [1]
在過去 var 作用域是根據函式作用域,而 let 、 const 則是以 { ... } Block 區塊做為作用域,來看看以下範例:
var name1 = 'Ryder'
let name2 = 'Ryder'
function test(){
	var name1 = 'Jack'
	let name2 = 'Jack'
}
test()
console.log(name1, name2)  // ?
結果是 Ryder, Ryder  ,這範例很好理解,不論是 var 還是 let , name = 'Jack' 的作用範圍都只在 test() 這個函式中,console 的位置則是在全域,自然都會是 Ryder ,那麼再來看看這個範例:
var name1 = 'Ryder'
let name2 = 'Ryder'
{
 var name1 = 'Jack'
}
{
 let name2 = 'Jack'
}
console.log(name1 , name2)  // ?
結果會是 Jack, Ryder ,這是因為上面提到的, let  是以 { ... } 區塊做為作用域,因此 let name1 = 'Jack' 這個語法的有效範圍只會存在於  { ... } 之中,而 var 則會被 { ... } 中的 var name1 = 'Jack' ,直接做替換,因此 name1 會是 'Jack' 。
這邊要補充一下, 這邊提到的 { ... } 並不是物件,而是一個作用域範圍,主要是為了搭配 let 、 const 特性 ES6 才引入的,不過實做中通常不會刻意使用 { ... } 去區分作用域。
在提升章節我們有提到,JavaScript 在編譯程式碼時,會分為兩個階段:
1.創造階段
2.執行階段var 變數會先在 創造階段 被建立,進入執行階段才會實際賦值,而在創造階段中的 var 變數,他的值會是 undefined ,如這個範例:
console.log(name1)  // undefined
var name1 = 'Ryder'
let 雖然也有提升概念,也同樣分成:
1.創造階段
2.執行階段
但在創造階段和 var 不同,let 在創造階段不是直接顯示 undefined ,他是進入一個 暫時性死區 (TDZ) 的狀況,MDN 文件是這麼描述的:
The variable is in a "temporal dead zone" from the start of the block until the initialization is processed
如果我們在 暫時性死區 的狀態去取得 let 變數的值,瀏覽器會跳錯,要注意的是,不同瀏覽器跳出的錯誤訊息會不同,如下範例:
FireFox 版本
console.log(name2)  // Uncaught ReferenceError: can't access lexical declaration 'name1' before initialization
let name2 = 'Ryder'
Chrome 版本
console.log(name2)  //Uncaught ReferenceError: name1 is not defined
let name2 = 'Ryder'
上面有提到到 let 、 const  是根據 { ... } 來區分作用域的,這邊要提一點的是 var  全域建立時,會是掛在 window  下。
而使用  let 、 const  在全域建立變數時,他並不會掛在  window  下,但我們若直接呼叫變數,他也會正確顯示,如範例
var name1= 'Ryder'
let name2 = 'Ryder'
window.name1 // 'Ryder'
window.name2 // undefined
name1 // 'Ryder'
name2 // 'Ryder'
這個原因是出在全域執行環境(Global space) 上面,首先這個全域執行環境其實是由兩個環境所組成的
因此全域執行環境(Global space) 其實是一個由雙環境組成的東西,一般來說我們是看不到 Declare Env 的。
所以 var 其實是基於 ObjectEnv 宣告並加入到 Declare Env,而 let、const 則是只會宣告在 Declare Env 中,這也就是為什麼我們無法在 Window 上面看到由 let、const 宣告的變數但卻又可以正常取得到值的原因。